using Microsoft.Extensions.Logging;
using RAG.Application.Dtos.Rag;
using RAG.Application.Services.Interfaces;
using RAG.Domain.Entities.App;
using RAG.Domain.Repositories;
using RAG.Domain.Services;
using System.Diagnostics;
using Microsoft.Extensions.Caching.Memory;
using System.Text.Json;

namespace RAG.Application.Services.Implementations;

/// <summary>
/// RAG问答服务实现
/// </summary>
public class RagQuestionAnswerService : IRagQuestionAnswerService
{
    private readonly IKnowledgeBaseRepository _knowledgeBaseRepository;
    private readonly IDocumentRepository _documentRepository;
    private readonly IDocumentChunkRepository _chunkRepository;
    private readonly IUserRepository _userRepository;
    private readonly IEmbeddingService _embeddingService;
    private readonly IChatService _chatService;
    private readonly IConversationService _conversationService;
    private readonly ISessionService _sessionService;
    private readonly ILogger<RagQuestionAnswerService> _logger;
    private readonly IMemoryCache _cache;

    public RagQuestionAnswerService(
        IKnowledgeBaseRepository knowledgeBaseRepository,
        IDocumentRepository documentRepository,
        IDocumentChunkRepository chunkRepository,
        IUserRepository userRepository,
        IEmbeddingService embeddingService,
        IChatService chatService,
        IConversationService conversationService,
        ISessionService sessionService,
        ILogger<RagQuestionAnswerService> logger,
        IMemoryCache cache)
    {
        _knowledgeBaseRepository = knowledgeBaseRepository;
        _documentRepository = documentRepository;
        _chunkRepository = chunkRepository;
        _userRepository = userRepository;
        _embeddingService = embeddingService;
        _chatService = chatService;
        _conversationService = conversationService;
        _sessionService = sessionService;
        _logger = logger;
        _cache = cache;
    }

    /// <summary>
    /// 基于知识库回答问题
    /// </summary>
    public async Task<RagQuestionAnswerResponseDto> AskQuestionAsync(RagQuestionAnswerRequestDto request)
    {
        var totalSw = Stopwatch.StartNew();
        var stageSw = Stopwatch.StartNew();
        void LogStage(string stage, string extra = "")
        {
            var ms = stageSw.ElapsedMilliseconds;
            _logger.LogInformation("[Perf][Ask] Stage={Stage} ElapsedMs={Elapsed} TotalMs={Total} {Extra}", stage, ms, totalSw.ElapsedMilliseconds, extra);
            stageSw.Restart();
        }

        try
        {
            _logger.LogInformation($"开始处理问题: {request.Question}");

            // 1. 将问题转换为向量
            var questionEmbedding = await GetOrAddQuestionEmbeddingAsync(request.Question);
            _logger.LogInformation($"问题向量化完成，维度: {questionEmbedding.Length}");
            LogStage("Embed", $"Dim={questionEmbedding.Length} QLen={request.Question.Length}");

            // 2. 在知识库中搜索相似内容（首次按用户阈值）
            var primaryThreshold = request.SimilarityThreshold;
            var similarKnowledges = await _knowledgeBaseRepository.SearchSimilarAsync(
                questionEmbedding,
                request.KnowledgeLimit,
                primaryThreshold); // 仓储已改为候选扩展 + 应用层过滤
            _logger.LogInformation($"初次检索(阈值={primaryThreshold:F2})找到 {similarKnowledges.Count} 条相似知识");
            Console.WriteLine($"===== 向量搜索结果 =====");
            Console.WriteLine($"问题: {request.Question}");
            Console.WriteLine($"相似度阈值: {primaryThreshold}");
            Console.WriteLine($"初次找到的知识数量: {similarKnowledges.Count}");
            Console.WriteLine($"AllowDirectAnswer: {request.AllowDirectAnswer}");
            LogStage("SearchPrimary", $"Threshold={primaryThreshold:F2} Hits={similarKnowledges.Count}");

            // 3. 如果没有找到相关知识
            if (!similarKnowledges.Any())
            {
                // 尝试自动回退：降低阈值（最多降 0.1，且不低于0.50）仅针对短查询或单词
                var isShortQuery = request.Question.Trim().Length <= 4; // 中文1-4字或英文短词
                if (isShortQuery)
                {
                    var fallbackThreshold = Math.Max(0.50, primaryThreshold - 0.10);
                    if (fallbackThreshold < primaryThreshold)
                    {
                        Console.WriteLine($"未命中，执行回退检索：降低阈值至 {fallbackThreshold:F2}");
                        _logger.LogInformation($"执行回退检索，阈值 {primaryThreshold:F2} -> {fallbackThreshold:F2}");
                        var fbSw = Stopwatch.StartNew();
                        var fallbackResults = await _knowledgeBaseRepository.SearchSimilarAsync(
                            questionEmbedding,
                            request.KnowledgeLimit,
                            fallbackThreshold);
                        var fbMs = fbSw.ElapsedMilliseconds;
                        if (fallbackResults.Any())
                        {
                            similarKnowledges = fallbackResults;
                            Console.WriteLine($"回退检索找到 {similarKnowledges.Count} 条结果 (阈值 {fallbackThreshold:F2})");
                            _logger.LogInformation($"回退检索找到 {similarKnowledges.Count} 条结果");
                            _logger.LogInformation("[Perf][Ask] Stage=SearchFallback ElapsedMs={Elapsed} Threshold={Threshold} Hits={Hits}", fbMs, fallbackThreshold, similarKnowledges.Count);
                        }
                        else
                        {
                            _logger.LogInformation("[Perf][Ask] Stage=SearchFallback ElapsedMs={Elapsed} Threshold={Threshold} Hits=0", fbMs, fallbackThreshold);
                        }
                        stageSw.Restart(); // 继续下一阶段
                    }
                }

                // 若回退后仍为空，进入原有逻辑
                if (!similarKnowledges.Any())
                {
                    _logger.LogInformation("知识库中未找到相关信息");
                    LogStage("SearchTotal", "Hits=0");

                    // 根据开关决定处理方式
                    if (request.AllowDirectAnswer)
                    {
                        // 允许直接回答：让Chat模型基于自身知识回答
                        _logger.LogInformation("===== 使用DeepSeek模型直接回答问题 =====");
                        Console.WriteLine("===== 使用DeepSeek模型直接回答问题 =====");
                        Console.WriteLine($"问题: {request.Question}");

                        var directAnswerContext = "请基于你的知识回答以下问题。注意：这个回答不是基于用户提供的知识库，而是基于你的训练数据。请提供准确、有用的信息。";

                        try
                        {
                            stageSw.Restart();
                            var directAnswer = await _chatService.GenerateResponseAsync(
                                request.Question,
                                directAnswerContext,
                                request.ChatHistory);
                            LogStage("ChatDirect", "Mode=NoKnowledge");

                            Console.WriteLine($"DeepSeek回答: {directAnswer}");

                            return new RagQuestionAnswerResponseDto
                            {
                                Answer = directAnswer,
                                KnowledgeSources = new List<KnowledgeSourceDto>(),
                                ProcessingTimeMs = totalSw.ElapsedMilliseconds,
                                HasRelevantKnowledge = false,
                                AnswerSource = "direct_answer",
                                SourceDescription = "由于知识库中没有相关信息，此回答来自AI模型的内置知识，可能不够准确或及时。建议补充相关知识到知识库中。"
                            };
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "DeepSeek模型调用失败");
                            Console.WriteLine($"DeepSeek模型调用失败: {ex.Message}");

                            return new RagQuestionAnswerResponseDto
                            {
                                Answer = $"抱歉，AI模型调用失败：{ex.Message}。请稍后再试。",
                                KnowledgeSources = new List<KnowledgeSourceDto>(),
                                ProcessingTimeMs = totalSw.ElapsedMilliseconds,
                                HasRelevantKnowledge = false,
                                AnswerSource = "error",
                                SourceDescription = "AI模型调用失败"
                            };
                        }
                    }
                    else
                    {
                        // 不允许直接回答：提示用户知识库中没有相关信息
                        _logger.LogInformation("知识库中没有相关信息，且不允许直接回答");

                        var noKnowledgeMessage = "抱歉，我在知识库中没有找到与您问题相关的信息。建议您：\n" +
                                               "1. 尝试使用不同的关键词重新提问\n" +
                                               "2. 将相关资料上传到知识库中\n" +
                                               "3. 如果希望我基于通用知识回答，请在请求中启用 'allowDirectAnswer' 选项";

                        return new RagQuestionAnswerResponseDto
                        {
                            Answer = noKnowledgeMessage,
                            KnowledgeSources = new List<KnowledgeSourceDto>(),
                            ProcessingTimeMs = totalSw.ElapsedMilliseconds,
                            HasRelevantKnowledge = false,
                            AnswerSource = "no_answer",
                            SourceDescription = "知识库中没有找到相关信息，且未启用直接回答模式"
                        };
                    }
                }
                else
                {
                    LogStage("SearchTotal", $"Hits={similarKnowledges.Count}");
                }
            }

            // 4. 构建上下文信息
            stageSw.Restart();
            var contextBuilder = new System.Text.StringBuilder();
            var knowledgeSources = new List<KnowledgeSourceDto>();

            foreach (var knowledge in similarKnowledges)
            {
                // 计算相似度得分（这里是一个简化的计算，实际应该使用向量距离）
                var similarityScore = CalculateSimilarityScore(questionEmbedding, knowledge.Embedding);

                contextBuilder.AppendLine($"【知识{knowledgeSources.Count + 1}】");
                contextBuilder.AppendLine($"标题: {knowledge.Title}");
                contextBuilder.AppendLine($"内容: {knowledge.Content}");
                contextBuilder.AppendLine();

                knowledgeSources.Add(new KnowledgeSourceDto
                {
                    Id = knowledge.Id,
                    Title = knowledge.Title,
                    Content = knowledge.Content,
                    SimilarityScore = similarityScore,
                    SourceDocument = knowledge.Chunk?.Document?.Title,
                    DocumentType = knowledge.DocumentType
                });
            }

            var context = contextBuilder.ToString();
            _logger.LogInformation($"上下文构建完成，长度: {context.Length}");
            LogStage("ContextBuild", $"ContextLen={context.Length} Sources={similarKnowledges.Count}");

            // 5. 调用Chat模型生成回答
            stageSw.Restart();
            // Chat答案缓存：基于 问题 + 顶层知识标题集合 构造 key，避免重复生成
            string cacheKey = "ans:" + request.Question + ":" + string.Join('|', similarKnowledges.Select(k => k.Title).OrderBy(t => t));
            if (_cache.TryGetValue(cacheKey, out string? cachedAnswer) && !string.IsNullOrWhiteSpace(cachedAnswer))
            {
                _logger.LogInformation("[Cache][Answer] Hit Question='{Question}'", request.Question);
                totalSw.Stop();
                return new RagQuestionAnswerResponseDto
                {
                    Answer = cachedAnswer,
                    KnowledgeSources = knowledgeSources,
                    ProcessingTimeMs = totalSw.ElapsedMilliseconds,
                    HasRelevantKnowledge = true,
                    AnswerSource = "cache",
                    SourceDescription = $"缓存命中，基于 {knowledgeSources.Count} 条知识(问题与来源组合未变化)"
                };
            }
            var answer = await _chatService.GenerateResponseAsync(request.Question, context, request.ChatHistory);
            _logger.LogInformation("AI回答生成完成");
            LogStage("ChatAnswer", $"Sources={similarKnowledges.Count}");

            totalSw.Stop();
            _logger.LogInformation("[Perf][Ask] Stage=Total ElapsedMs={Elapsed} Question='{Question}' Hits={Hits}", totalSw.ElapsedMilliseconds, request.Question, similarKnowledges.Count);

            // 设置答案缓存（短问题或上下文较短才缓存，以避免占用过多内存）
            if (request.Question.Length <= 32 && context.Length <= 5000)
            {
                _cache.Set(cacheKey, answer, new MemoryCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30),
                    Size = Math.Max(1, answer.Length) // 简单大小估计
                });
                _logger.LogInformation("[Cache][Answer] Set Question='{Question}' Len={Len}", request.Question, answer.Length);
            }

            // 保存对话记录到数据库
            try
            {
                var userId = request.UserId ?? Guid.Empty;
                var sessionId = await _sessionService.GetOrCreateSessionAsync(request.SessionId, userId, "RAG问答会话");
                var sourceDocuments = knowledgeSources.Any() ? JsonSerializer.Serialize(knowledgeSources) : null;
                
                var conversation = new Conversations
                {
                    Id = Guid.NewGuid(),
                    Question = request.Question,
                    Answer = answer,
                    SourceDocuments = sourceDocuments,
                    ConfidenceScore = knowledgeSources.Any() ? (decimal)knowledgeSources.Max(s => s.SimilarityScore) : null,
                    ResponseTimeMs = (int)totalSw.ElapsedMilliseconds,
                    UserId = userId,
                    SessionId = sessionId,
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow,
                    CreatedBy = userId,
                    UpdatedBy = userId
                };

                await _conversationService.SaveConversationAsync(conversation);
                _logger.LogInformation("对话记录保存成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "保存对话记录时发生错误");
                // 不抛出异常，避免影响主要功能
            }

            return new RagQuestionAnswerResponseDto
            {
                Answer = answer,
                KnowledgeSources = knowledgeSources,
                ProcessingTimeMs = totalSw.ElapsedMilliseconds,
                HasRelevantKnowledge = true,
                AnswerSource = "knowledge_base",
                SourceDescription = $"基于知识库中的 {knowledgeSources.Count} 条相关信息生成的回答"
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"处理问题时发生错误: {request.Question}");
            totalSw.Stop();
            _logger.LogInformation("[Perf][Ask] Stage=Total ElapsedMs={Elapsed} (WithError) Question='{Question}'", totalSw.ElapsedMilliseconds, request.Question);

            return new RagQuestionAnswerResponseDto
            {
                Answer = "抱歉，处理您的问题时发生了错误，请稍后重试。",
                KnowledgeSources = new List<KnowledgeSourceDto>(),
                ProcessingTimeMs = totalSw.ElapsedMilliseconds,
                HasRelevantKnowledge = false
            };
        }
    }

    /// <summary>
    /// 仅做 检索 + 上下文构建，返回给流式调用方，减少等待，真正实时从第一 token 输出
    /// </summary>
    public async Task<RagPreparationResult> PrepareStreamingAsync(RagQuestionAnswerRequestDto request)
    {
        var result = new RagPreparationResult { Question = request.Question };
        // 嵌入
        var embedding = await GetOrAddQuestionEmbeddingAsync(request.Question);
        var similar = await _knowledgeBaseRepository.SearchSimilarAsync(embedding, request.KnowledgeLimit, request.SimilarityThreshold);
        // 回退逻辑（复用 AskQuestionAsync 中部分，简化）
        if (!similar.Any())
        {
            var isShort = request.Question.Trim().Length <= 4;
            if (isShort)
            {
                var fb = Math.Max(0.50, request.SimilarityThreshold - 0.10);
                if (fb < request.SimilarityThreshold)
                {
                    var fbList = await _knowledgeBaseRepository.SearchSimilarAsync(embedding, request.KnowledgeLimit, fb);
                    if (fbList.Any()) similar = fbList;
                }
            }
        }
        // 无知识
        if (!similar.Any())
        {
            if (!request.AllowDirectAnswer)
            {
                result.StreamAnswer = false;
                result.AnswerSource = "no_answer";
                result.ImmediateAnswer = "抱歉，知识库中没有找到相关信息，可尝试换关键词或上传资料。";
                result.SourceDescription = "知识库为空";
                return result;
            }
            // 直接回答场景：仍然走流式，但上下文提示模型说明
            result.HasRelevantKnowledge = false;
            result.AnswerSource = "direct_answer";
            result.DirectAnswerContext = "请基于你的常识回答用户问题，说明这是通用知识回答。";
            return result;
        }
        // 构建上下文
        var ctxSb = new System.Text.StringBuilder();
        var sources = new List<KnowledgeSourceDto>();
        var questionEmbedding = embedding; // reuse var name clarity
        foreach (var k in similar)
        {
            var score = CalculateSimilarityScore(questionEmbedding, k.Embedding);
            ctxSb.AppendLine($"【知识】{k.Title}");
            ctxSb.AppendLine(k.Content);
            ctxSb.AppendLine();
            sources.Add(new KnowledgeSourceDto { Id = k.Id, Title = k.Title, Content = k.Content, SimilarityScore = score, SourceDocument = k.Chunk?.Document?.Title, DocumentType = k.DocumentType });
        }
        result.KnowledgeSources = sources;
        result.Context = ctxSb.ToString();
        result.HasRelevantKnowledge = true;
        result.AnswerSource = "knowledge_base";
        return result;
    }

    private async Task<float[]> GetOrAddQuestionEmbeddingAsync(string question)
    {
        // 短文本缓存策略：长度 <= 8 且全是中英文/数字则缓存 24h
        var keyEligible = question.Length <= 8 && question.All(c => char.IsLetterOrDigit(c) || char.IsWhiteSpace(c) || c >= 0x4e00 && c <= 0x9fa5);
        if (!keyEligible)
        {
            return await _embeddingService.GenerateTextEmbeddingAsync(question);
        }

        var cacheKey = $"embed:q:{question}";
        if (_cache.TryGetValue(cacheKey, out float[]? cached))
        {
            if (cached != null)
            {
                _logger.LogInformation("[Cache][Embed] Hit Question='{Question}'", question);
                return cached; // cached 已非空
            }
            // 罕见：缓存存在但值为 null（不应出现），直接移除并重新生成
            _cache.Remove(cacheKey);
        }

        var embedding = await _embeddingService.GenerateTextEmbeddingAsync(question);
        _cache.Set(cacheKey, embedding, new MemoryCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(24),
            Size = embedding.Length // 需在 Program 中配置 SizeLimit
        });
        _logger.LogInformation("[Cache][Embed] Set Question='{Question}' Dim={Dim}", question, embedding.Length);
        return embedding;
    }

    /// <summary>
    /// 获取知识库中的相似内容
    /// </summary>
    public async Task<List<SimilarKnowledgeDto>> GetSimilarKnowledgeAsync(string question, int limit = 5, double threshold = 0.7)
    {
        try
        {
            // 将问题转换为向量
            var questionEmbedding = await _embeddingService.GenerateTextEmbeddingAsync(question);

            // 搜索相似知识
            var similarKnowledges = await _knowledgeBaseRepository.SearchSimilarAsync(questionEmbedding, limit, threshold);

            return similarKnowledges.Select(k => new SimilarKnowledgeDto
            {
                Id = k.Id,
                Title = k.Title,
                Content = k.Content,
                SimilarityScore = CalculateSimilarityScore(questionEmbedding, k.Embedding),
                SourceInfo = k.Chunk?.Document?.Title ?? "未知来源"
            }).ToList();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"获取相似知识时发生错误: {question}");
            return new List<SimilarKnowledgeDto>();
        }
    }

    /// <summary>
    /// 上传知识内容并向量化存储
    /// </summary>
    public async Task<KnowledgeUploadResponseDto> UploadKnowledgeAsync(KnowledgeUploadRequestDto request)
    {
        try
        {
            _logger.LogInformation($"开始上传知识: {request.Title}");
            var totalSw = Stopwatch.StartNew();
            var stageSw = Stopwatch.StartNew();
            void LogStage(string stage, string extra = "") => _logger.LogInformation("[Perf][UploadText] Stage={Stage} ElapsedMs={Elapsed} TotalMs={Total} {Extra}", stage, stageSw.ElapsedMilliseconds, totalSw.ElapsedMilliseconds, extra);

            // 1. 获取或创建用户
            Users? user = null;
            Guid actualUserId;

            if (request.UserId.HasValue)
            {
                // 如果提供了UserId，验证用户是否存在
                user = await _userRepository.GetByIdAsync(request.UserId.Value);
                if (user == null)
                {
                    return new KnowledgeUploadResponseDto
                    {
                        Success = false,
                        Message = "指定的用户不存在"
                    };
                }
                actualUserId = request.UserId.Value;
            }
            else
            {
                // 如果没有提供UserId，创建或使用默认用户
                user = await GetOrCreateDefaultUserAsync();
                actualUserId = user.Id;
            }

            // 2. 创建文档
            var document = new Documents
            {
                Id = Guid.NewGuid(),
                Title = request.Title,
                FileName = $"{request.Title}.{request.DocumentType.TrimStart('.')}",
                FilePath = $"knowledge/{Guid.NewGuid()}.{request.DocumentType.TrimStart('.')}",
                FileType = request.DocumentType,
                FileSize = $"{request.Content.Length} bytes",
                Description = "通过API上传的知识内容",
                Tags = "知识库,API上传",
                AccessLevel = "internal",
                Status = "completed",
                UserId = actualUserId,
                User = user,
                CreatedBy = actualUserId,
                UpdatedBy = actualUserId
            };

            await _documentRepository.CreateAsync(document);

            // 3. 创建文档块
            var chunk = new DocumentChunks
            {
                Id = Guid.NewGuid(),
                ChunkIndex = 0,
                Content = request.Content,
                TokenCount = EstimateTokenCount(request.Content),
                Document = document,
                CreatedBy = actualUserId,
                UpdatedBy = actualUserId
            };

            await _chunkRepository.CreateAsync(chunk);

            // 4. 生成向量嵌入（组合标题和内容以获得更好的语义表示）
            var combinedText = $"{request.Title}. {request.Content}";
            var embedding = await _embeddingService.GenerateTextEmbeddingAsync(combinedText); // 现已统一使用多模态模型
            _logger.LogInformation($"知识向量化完成，维度: {embedding.Length}，文本长度: {combinedText.Length}");
            LogStage("Embed", $"Dim={embedding.Length} TextLen={combinedText.Length}");

            // 5. 创建知识库条目
            var knowledgeBase = new KnowledgeBase
            {
                Id = Guid.NewGuid(),
                Embedding = embedding,
                ChunkId = chunk.Id,
                Content = request.Content,
                DocumentType = request.DocumentType,
                EmbeddingType = request.EmbeddingType,
                ImageUrl = request.ImageUrl,
                IsChunked = request.IsChunked,
                Metadata = request.Metadata,
                Source = request.Source,
                Title = request.Title,
                CreatedBy = actualUserId,
                UpdatedBy = actualUserId
            };

            await _knowledgeBaseRepository.CreatedAsync(knowledgeBase);

            _logger.LogInformation($"知识上传完成: {request.Title}");
            totalSw.Stop();
            _logger.LogInformation("[Perf][UploadText] Stage=Total ElapsedMs={Elapsed} Title='{Title}'", totalSw.ElapsedMilliseconds, request.Title);

            return new KnowledgeUploadResponseDto
            {
                KnowledgeId = knowledgeBase.Id,
                DocumentId = document.Id,
                ChunkId = chunk.Id,
                Success = true,
                Message = "知识上传成功",
                EmbeddingDimension = embedding.Length
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"上传知识时发生错误: {request.Title}");
            return new KnowledgeUploadResponseDto
            {
                Success = false,
                Message = $"上传失败: {ex.Message}"
            };
        }
    }

    /// <summary>
    /// 上传多模态知识内容并向量化存储
    /// </summary>
    public async Task<KnowledgeUploadResponseDto> UploadMultimodalKnowledgeAsync(MultimodalKnowledgeUploadRequestDto request)
    {
        try
        {
            _logger.LogInformation($"开始上传多模态知识: {request.Title}");
            var totalSw = Stopwatch.StartNew();
            var stageSw = Stopwatch.StartNew();
            void LogStage(string stage, string extra = "") => _logger.LogInformation("[Perf][UploadMulti] Stage={Stage} ElapsedMs={Elapsed} TotalMs={Total} {Extra}", stage, stageSw.ElapsedMilliseconds, totalSw.ElapsedMilliseconds, extra);

            // 验证输入参数
            if (string.IsNullOrWhiteSpace(request.Title))
            {
                return new KnowledgeUploadResponseDto
                {
                    Success = false,
                    Message = "标题不能为空"
                };
            }

            if (string.IsNullOrWhiteSpace(request.ImageBase64) && string.IsNullOrWhiteSpace(request.ImageUrl))
            {
                return new KnowledgeUploadResponseDto
                {
                    Success = false,
                    Message = "必须提供图片数据（ImageBase64或ImageUrl）"
                };
            }

            // 1. 处理用户
            Users user;
            Guid actualUserId;

            if (request.UserId.HasValue && request.UserId.Value != Guid.Empty)
            {
                var inputUserId = request.UserId.Value;
                Users? fetched = await _userRepository.GetByIdAsync(inputUserId);
                if (fetched is null)
                {
                    return new KnowledgeUploadResponseDto
                    {
                        Success = false,
                        Message = "指定的用户不存在"
                    };
                }
                user = fetched; // 这里之后 user 不为 null
                actualUserId = inputUserId;
            }
            else
            {
                user = await GetOrCreateDefaultUserAsync();
                actualUserId = user.Id;
            }

            // 2. 处理图片数据
            byte[] imageData;
            string imageContent = string.Empty;

            if (!string.IsNullOrWhiteSpace(request.ImageBase64))
            {
                try
                {
                    // 移除data:image/...;base64,前缀（如果存在）
                    var base64Data = request.ImageBase64;
                    if (base64Data.Contains(","))
                    {
                        base64Data = base64Data.Substring(base64Data.IndexOf(",") + 1);
                    }

                    imageData = Convert.FromBase64String(base64Data);

                    // 检查图片大小（3MB限制）
                    if (imageData.Length > 3 * 1024 * 1024)
                    {
                        return new KnowledgeUploadResponseDto
                        {
                            Success = false,
                            Message = "图片大小不能超过3MB"
                        };
                    }

                    imageContent = $"图片文件: {request.ImageFileName ?? "image.jpg"}";
                }
                catch (Exception ex)
                {
                    return new KnowledgeUploadResponseDto
                    {
                        Success = false,
                        Message = $"图片Base64解码失败: {ex.Message}"
                    };
                }
            }
            else if (!string.IsNullOrWhiteSpace(request.ImageUrl))
            {
                try
                {
                    using var httpClient = new HttpClient();
                    imageData = await httpClient.GetByteArrayAsync(request.ImageUrl);

                    // 检查图片大小（3MB限制）
                    if (imageData.Length > 3 * 1024 * 1024)
                    {
                        return new KnowledgeUploadResponseDto
                        {
                            Success = false,
                            Message = "图片大小不能超过3MB"
                        };
                    }

                    imageContent = $"图片URL: {request.ImageUrl}";
                }
                catch (Exception ex)
                {
                    return new KnowledgeUploadResponseDto
                    {
                        Success = false,
                        Message = $"从URL下载图片失败: {ex.Message}"
                    };
                }
            }
            else
            {
                return new KnowledgeUploadResponseDto
                {
                    Success = false,
                    Message = "未提供有效的图片数据"
                };
            }

            // 3. 创建文档
            var document = new Documents
            {
                Id = Guid.NewGuid(),
                Title = request.Title,
                FileName = request.ImageFileName ?? $"{request.Title}.jpg",
                FilePath = $"multimodal/{Guid.NewGuid()}.jpg",
                FileType = request.DocumentType,
                FileSize = $"{imageData.Length} bytes",
                Description = "通过API上传的多模态内容（图片+文本）",
                Tags = "知识库,多模态,API上传",
                AccessLevel = "internal",
                Status = "completed",
                UserId = actualUserId,
                User = user,
                CreatedBy = actualUserId,
                UpdatedBy = actualUserId
            };

            await _documentRepository.CreateAsync(document);

            // 4. 创建文档块
            // 之前格式为: "{imageContent}. {文本}" 会导致 URL 后面多一个点 + 空格，显示不自然
            // 调整为换行分隔，如果有文本则: "{imageContent}\n{文本}"，否则仅图片描述
            string combinedContent = imageContent;
            if (!string.IsNullOrWhiteSpace(request.Content))
            {
                combinedContent = imageContent + "\n" + request.Content.Trim();
            }

            var chunk = new DocumentChunks
            {
                Id = Guid.NewGuid(),
                ChunkIndex = 0,
                Content = combinedContent,
                TokenCount = EstimateTokenCount(combinedContent),
                Document = document,
                CreatedBy = actualUserId,
                UpdatedBy = actualUserId
            };

            await _chunkRepository.CreateAsync(chunk);

            // 5. 生成多模态向量嵌入
            var embedding = await _embeddingService.GenerateMultimodalEmbeddingAsync(imageData, request.Content);
            _logger.LogInformation($"多模态向量化完成（统一模型），维度: {embedding.Length}，图片大小: {imageData.Length} bytes");
            LogStage("Embed", $"Dim={embedding.Length} ImgBytes={imageData.Length} TextLen={(request.Content ?? string.Empty).Length}");

            // 6. 创建多模态主知识库条目（不再生成文本代理记录，统一模型无需代理）
            var knowledgeBase = new KnowledgeBase
            {
                Id = Guid.NewGuid(),
                Embedding = embedding,
                ChunkId = chunk.Id,
                Content = combinedContent,
                DocumentType = request.DocumentType,
                EmbeddingType = "multimodal-embedding",
                ImageUrl = request.ImageUrl,
                IsChunked = false,
                Metadata = request.Metadata,
                Source = request.Source,
                Title = request.Title,
                CreatedBy = actualUserId,
                UpdatedBy = actualUserId
            };

            await _knowledgeBaseRepository.CreatedAsync(knowledgeBase);
            _logger.LogInformation($"多模态记录已创建(统一模型): {knowledgeBase.Id}");
            _logger.LogInformation($"多模态知识上传完成: {request.Title}");
            totalSw.Stop();
            _logger.LogInformation("[Perf][UploadMulti] Stage=Total ElapsedMs={Elapsed} Title='{Title}'", totalSw.ElapsedMilliseconds, request.Title);

            return new KnowledgeUploadResponseDto
            {
                KnowledgeId = knowledgeBase.Id,
                DocumentId = document.Id,
                ChunkId = chunk.Id,
                Success = true,
                Message = "多模态知识上传成功(统一模型)",
                EmbeddingDimension = embedding.Length
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"上传多模态知识时发生错误: {request.Title}");
            return new KnowledgeUploadResponseDto
            {
                Success = false,
                Message = $"上传失败: {ex.Message}"
            };
        }
    }

    /// <summary>
    /// 计算相似度得分（简化版本）
    /// </summary>
    private double CalculateSimilarityScore(float[] vector1, float[] vector2)
    {
        if (vector1.Length != vector2.Length)
            return 0.0;

        double dotProduct = 0.0;
        double magnitude1 = 0.0;
        double magnitude2 = 0.0;

        for (int i = 0; i < vector1.Length; i++)
        {
            dotProduct += vector1[i] * vector2[i];
            magnitude1 += vector1[i] * vector1[i];
            magnitude2 += vector2[i] * vector2[i];
        }

        if (magnitude1 == 0.0 || magnitude2 == 0.0)
            return 0.0;

        return dotProduct / (Math.Sqrt(magnitude1) * Math.Sqrt(magnitude2));
    }

    /// <summary>
    /// 估算Token数量
    /// </summary>
    private int EstimateTokenCount(string text)
    {
        // 简单的中文Token估算：字符数 / 1.5
        return (int)Math.Ceiling(text.Length / 1.5);
    }

    /// <summary>
    /// 获取或创建默认用户
    /// </summary>
    private async Task<Users> GetOrCreateDefaultUserAsync()
    {
        // 尝试获取默认用户
        var defaultUser = await _userRepository.GetByUserNameAsync("system_default");

        if (defaultUser != null)
        {
            return defaultUser;
        }

        // 创建默认用户
        var newDefaultUser = new Users
        {
            Id = Guid.NewGuid(),
            UserName = "system_default",
            Email = "system@rag.local",
            Password = "N/A", // 系统用户不需要密码
            Status = "active",
            AvatarUrl = null,
            PhoneNumber = null,
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };

        return await _userRepository.CreateAsync(newDefaultUser);
    }

    /// <summary>
    /// 清理知识库数据
    /// </summary>
    public async Task<KnowledgeCleanupResponseDto> CleanupKnowledgeBaseAsync()
    {
        try
        {
            _logger.LogInformation("开始清理知识库数据...");

            // 获取所有知识库记录
            var allKnowledge = await _knowledgeBaseRepository.GetAllAsync();
            var knowledgeList = allKnowledge.ToList();
            var deleteCount = knowledgeList.Count;

            // 删除所有知识库记录
            foreach (var knowledge in knowledgeList)
            {
                await _knowledgeBaseRepository.DeleteAsync(knowledge.Id);
            }

            // 也可以清理相关的文档和文档块（如果需要的话）
            var allDocuments = await _documentRepository.GetAllAsync();
            var documentList = allDocuments.ToList();

            foreach (var doc in documentList)
            {
                await _documentRepository.DeleteAsync(doc.Id);
            }

            // 注意：DocumentChunkRepository可能没有GetAllAsync方法，我们跳过这部分
            // 当删除Document时，相关的Chunks应该会级联删除

            _logger.LogInformation($"知识库清理完成，删除了 {deleteCount} 条知识记录，{documentList.Count} 个文档");

            return new KnowledgeCleanupResponseDto
            {
                DeletedCount = deleteCount,
                Success = true,
                Message = $"知识库清理完成，删除了 {deleteCount} 条知识记录，{documentList.Count} 个文档",
                CleanupTime = DateTime.UtcNow
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "清理知识库时发生错误");

            return new KnowledgeCleanupResponseDto
            {
                DeletedCount = 0,
                Success = false,
                Message = $"清理失败: {ex.Message}",
                CleanupTime = DateTime.UtcNow
            };
        }
    }
}
